package com.wangsd.web.weixin.controller;

import com.google.gson.JsonObject;
import com.wangsd.common.component.WxComponentService;
import com.wangsd.common.entity.Result;
import com.wangsd.web.weixin.service.WxComponentBindService;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
import me.chanjar.weixin.open.bean.result.WxOpenQueryAuthResult;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;

/**
 * 微信开放平台请求controller
 */
@Slf4j
@RestController
@RequestMapping("/api/open")
public class WechatApiController {

    @Value("${notify_url}")
    private String notify_url;

    @Autowired
    WxComponentService wxComponentService;
    @Autowired
    WxComponentBindService wxComponentBindService;

    /**
     * 创建虚拟开放平台并绑定公众号和小程序
     *
     * @param merchantId 商户id
     * @param platform   来源平台
     * @param appid      公众号id
     * @param miniAppid
     * @return
     */
    @GetMapping("/bind")
    public Object bind(Long merchantId, String platform, String appid, String miniAppid,String appSecret) {
        if (merchantId == null) {
            return Result.fail("商户ID不能为空");
        }
        if (StringUtils.isBlank(platform)) {
            return Result.fail("平台不能为空");
        }
        if (StringUtils.isBlank(appid)) {
            return Result.fail("公众号ID不能为空");
        }
        if (StringUtils.isBlank(miniAppid)) {
            return Result.fail("小程序ID不能为空");
        }
        if (StringUtils.isBlank(appSecret)) {
            return Result.fail("公众号Secret不能为空");
        }
        try {
            wxComponentBindService.createAndBulid(merchantId, platform, appid, miniAppid,appSecret);
            return Result.success();
        } catch (Exception e) {
            return Result.fail(e.getMessage());
        }
    }


    /**
     * 创建开放平台帐号并绑定公众号/小程序
     *
     * @param appid
     * @return
     */
    @GetMapping("/openCreate")
    public Object openCreate(String appid) {
        log.debug(appid);
        String url = "https://api.weixin.qq.com/cgi-bin/open/create?access_token=";
        try {
            String access_token = wxComponentService.getWxOpenComponentService().getAuthorizerAccessToken(appid, false);
            JsonObject param = new JsonObject();
            param.addProperty("appid", appid);
            String str = wxComponentService.post(url + access_token, param.toString());
            return str;
        } catch (WxErrorException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取公众号/小程序所绑定的开放平台帐号
     *
     * @param appid
     * @return
     */
    @GetMapping("/openGet")
    public Object openGet(String appid) {
        log.debug(appid);
        String url = "https://api.weixin.qq.com/cgi-bin/open/get?access_token=";
        try {
            String access_token = wxComponentService.getWxOpenComponentService().getAuthorizerAccessToken(appid, false);
            JsonObject param = new JsonObject();
            param.addProperty("appid", appid);
            String str = wxComponentService.post(url + access_token, param.toString());
            return str;
        } catch (WxErrorException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将公众号/小程序绑定到开放平台帐号下
     *
     * @param appid
     * @param open_appid
     * @return
     */
    @GetMapping("/openBind")
    public Object openBind(String appid, String open_appid) {
        log.debug(appid);
        String url = "https://api.weixin.qq.com/cgi-bin/open/bind?access_token=";
        try {
            String access_token = wxComponentService.getWxOpenComponentService().getAuthorizerAccessToken(appid, false);
            JsonObject param = new JsonObject();
            param.addProperty("appid", appid);
            param.addProperty("open_appid", open_appid);
            String str = wxComponentService.post(url + access_token, param.toString());
            return str;
        } catch (WxErrorException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将公众号/小程序从开放平台帐号下解绑
     *
     * @param appid
     * @param open_appid
     * @return
     */
    @GetMapping("/openUnbind")
    public Object openUnbind(String appid, String open_appid) {
        log.debug(appid);
        String url = "https://api.weixin.qq.com/cgi-bin/open/unbind?access_token=";
        try {
            String access_token = wxComponentService.getWxOpenComponentService().getAuthorizerAccessToken(appid, false);
            JsonObject param = new JsonObject();
            param.addProperty("appid", appid);
            param.addProperty("open_appid", open_appid);
            String str = wxComponentService.post(url + access_token, param.toString());
            return str;
        } catch (WxErrorException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 显示授权链接(测试用)
     *
     * @return
     */
    @GetMapping("/go")
    public String gotoPreAuthUrlShow() {
        return "<a href='toAuth'>go</a>";
    }

    /**
     * 解决直接访问toAuth方法报错:
     * 请确认授权入口页所在域名，与授权后回调页所在域名相同，并且，此两者都必须与申请第三方平台时填写的授权发起页域名相同。授权入口页所在域名：空
     *
     * @return
     */
    @GetMapping("/authGo")
    @ResponseBody
    public String authGo() {
        return "<script>location.href ='toAuth'; </script>";
    }

    /**
     * 发起授权(公众号授权给第三方平台)
     *
     * @param request
     * @param response
     */
    @GetMapping("/toAuth")
    public void toAuth(HttpServletRequest request, HttpServletResponse response) {
        String redirect = notify_url + "/api/open/authCallback";
        try {
            String url = wxComponentService.getWxOpenComponentService().getPreAuthUrl(redirect);
            // 添加来源，解决302跳转来源丢失的问题
            response.addHeader("Referer", notify_url);
            response.sendRedirect(url);
        } catch (WxErrorException | IOException e) {
            log.error("toAuth", e);
            throw new RuntimeException(e);
        }
    }


    /**
     * 公众号授权给第三方平台(成功回调)
     *
     * @param auth_code
     * @return
     */
    @RequestMapping("/authCallback")
    public Object authCallback(String auth_code) {
        try {
            log.debug("-----公众号授权给第三方平台成功回调code-----", auth_code);
            WxOpenQueryAuthResult queryAuthResult = wxComponentService.getWxOpenComponentService().getQueryAuth(auth_code);
            //return queryAuthResult;
            return "<script>alert('授权成功!');window.close();</script>";
        } catch (WxErrorException e) {
            log.error("authCallback", e);
            throw new RuntimeException(e);
        }
    }


    /**
     * 开放平台第三方平台代公众号网页授权
     *
     * @param appid 公众号appid
     * @param scope snsapi_base或者snsapi_userinfo
     * @param state 重定向后会带上 state 参数，开发者可以填写任意参数值，最多 128 字节
     * @param from  返回地址
     */
    @GetMapping("/authorize")
    public Object authorize(HttpServletResponse response,
                            String appid, String scope, String state, String from) {
        //String userAgent = request.getHeader(HTTP.USER_AGENT);//"wechat","alipay","dingtalk"
        if (StringUtils.isBlank(appid)) {
            return Result.fail("appid不能为空");
        }
//        if (StringUtils.isBlank(from)) {
//            return Result.fail("from不能为空");
//        }
        if (StringUtils.isBlank(scope)) {
            scope = "snsapi_base";
        }
        String redirect = notify_url + "/api/open/authorizeCallbak";
        try {
            if (StringUtils.isNotBlank(from)) {
                redirect += "?from=" + URLEncoder.encode(from, "UTF-8");
            }

            String url = wxComponentService.getWxOpenComponentService().oauth2buildAuthorizationUrl(appid, redirect, scope, state);
            log.debug("代公众号网页授权:{}", url);
            response.sendRedirect(url);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Result.success();
    }

    /**
     * （第三方平台）代公众号网页授权回调
     *
     * @param appid 公众号appid
     * @param code
     * @param state 重定向后会带上 state 参数，开发者可以填写任意参数值，最多 128 字节
     * @param from  返回地址
     */
    @RequestMapping("/authorizeCallbak")
    public Object authorizeCallbak(HttpServletResponse response,
                                   String appid, String code, String state, String from) {
        log.debug("代公众号网页授权回调from={}", from);
        log.debug("代公众号网页授权回调appid={}", appid);
        log.debug("代公众号网页授权回调code={}", code);
        try {
            WxMpOAuth2AccessToken accessToken = wxComponentService.getWxOpenComponentService().oauth2getAccessToken(appid, code);
            String openid = accessToken.getOpenId();

            if (StringUtils.isNotBlank(from)) {
                log.debug("回调数据={}", from + "&openid=" + openid + "&appid=" + appid + "&state=" + state);
                if (from.contains("?")) {
                    response.sendRedirect(from + "&openid=" + openid + "&appid=" + appid + "&state=" + state);
                } else {
                    response.sendRedirect(from + "?openid=" + openid + "&appid=" + appid + "&state=" + state);
                }
            }
            return openid;
        } catch (WxErrorException | IOException e) {
            log.error("authorizeCallbak", e);
            throw new RuntimeException(e);
        }
    }

}
